#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <windows.h>

#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4

int sleeptime = 320; // 默认速度
int score_per_food = 2; // 吃到食物的得分，默认为 2 分

void game();
void gameover(int);

int direction = RIGHT;
#define MAX_SNAKE_LENGTH 100  // 最大蛇长

typedef struct {
    int x[MAX_SNAKE_LENGTH];  // 蛇的 X 坐标
    int y[MAX_SNAKE_LENGTH];  // 蛇的 Y 坐标
    int length;               // 蛇的长度
    int dx, dy;               // 当前蛇头的移动方向
} Snake;

Snake snake;
int foodX = -1, foodY = -1;  // 食物的坐标，初始为无效坐标

void SetConsoleColor(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

void save_highscore(int score) {
    FILE *file = fopen("save.txt", "w");  // 打开 save.txt 文件，若不存在则创建
    if (file == NULL) {
        printf("无法打开文件保存最高分！\n");
        return;
    }
    fprintf(file, "%d", score);  // 把当前得分写入文件
    fclose(file);  // 关闭文件
}

int load_highscore() {
    FILE *file = fopen("save.txt", "r");  // 打开 save.txt 文件读取最高分
    int highscore = 0;
    if (file != NULL) {
        fscanf(file, "%d", &highscore);  // 读取文件中的最高分
        fclose(file);
    }
    return highscore;
}


void explation() {
    
    printf("游戏说明：\n");
    printf("1. 游戏的目标是通过控制蛇的移动，吃到食物，尽可能长时间生存。\n");
    printf("2. 蛇会随着吃到食物而变长，每次吃到食物得分+1。\n");
    printf("3. 蛇不能碰到墙壁或自己的身体，否则游戏结束。\n");
    printf("4. 按键操作：\n");
    printf("   - 使用 WASD 键控制蛇的移动方向。\n");
    printf("   - 按 F1 加速，按 F2 减速。\n");
    printf("5. 游戏结束后，你可以选择重玩或者退出游戏。\n");
    printf("\n按任意键返回主菜单...");
    getchar();  // 获取输入，防止用户直接跳过
    getchar();  // 再次获取输入，以便继续
}


// 检查蛇是否与自己发生碰撞
int check_self_collision() {
    for (int i = 1; i < snake.length; i++) {
        if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i]) {
            return 1;  // 蛇头与蛇身重合，咬到自己
        }
    }
    return 0;  // 没有咬到自己
}

void speedup() {
    if (sleeptime > 10) {
        sleeptime = 10;  // 加速，最小时间间隔为 10
    }
    if (score_per_food < 2) {
        score_per_food = 2;  // 防止得分为 1 以下，确保吃到食物得分至少为 2
    }
}

void speeddown() {
    if (sleeptime < 350) {
        sleeptime += 30;  // 减速，增加时间间隔
    }
    if (score_per_food > 1) {
        score_per_food -= 1;  // 减少得分，确保最低得分为 1
    }
}

// 检查蛇是否撞墙
int check_wall_collision() {
    int width = 50;  // 地图宽度
    int height = 20; // 地图高度

    if (snake.x[0] <= 0 || snake.x[0] >= width - 1 || snake.y[0] <= 0 || snake.y[0] >= height - 1) {
        return 1;  // 撞墙
    }
    return 0;  // 没有撞墙
}

// 处理用户的输入，改变蛇的方向
void handle_input() {
    if (_kbhit()) {  // 检查是否有键盘输入
        char key = _getch();  // 获取输入的字符
        switch (key) {
            case 'w':
            case 'W':
                if (direction != DOWN) {  // 防止反向移动
                    direction = UP;
                    snake.dx = 0;
                    snake.dy = -1;
                }
                break;
            case 's':
            case 'S':
                if (direction != UP) {  // 防止反向移动
                    direction = DOWN;
                    snake.dx = 0;
                    snake.dy = 1;
                }
                break;
            case 'a':
            case 'A':
                if (direction != RIGHT) {  // 防止反向移动
                    direction = LEFT;
                    snake.dx = -1;
                    snake.dy = 0;
                }
                break;
            case 'd':
            case 'D':
                if (direction != LEFT) {  // 防止反向移动
                    direction = RIGHT;
                    snake.dx = 1;
                    snake.dy = 0;
                }
                break;
            case 0x3B: // F1 键
                speedup();  // 加速
                break;
            case 0x3C: // F2 键
                speeddown();  // 减速
                break;
            default:
                break;
        }
    }
}
void hide_cursor() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cursorInfo;
    GetConsoleCursorInfo(hConsole, &cursorInfo);
    cursorInfo.dwSize = 1;  // 设置为最小尺寸
    cursorInfo.bVisible = FALSE;  // 设置为不可见
    SetConsoleCursorInfo(hConsole, &cursorInfo);
}
// 移动蛇
void move_snake() {
    // 从尾部开始移动每一部分
    for (int i = snake.length - 1; i > 0; i--) {
        snake.x[i] = snake.x[i - 1];
        snake.y[i] = snake.y[i - 1];
    }

    // 更新蛇头位置
    snake.x[0] += snake.dx;
    snake.y[0] += snake.dy;
}
// 绘制蛇
void printsnake() {
    SetConsoleColor(10);  // 绿色
    COORD coord;
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    // 绘制蛇的身体
    for (int i = 0; i < snake.length; i++) {
        coord.X = snake.x[i];  // 使用蛇身的 X 坐标
        coord.Y = snake.y[i];  // 使用蛇身的 Y 坐标
        SetConsoleCursorPosition(hConsole, coord);
        printf("*");  // 绘制蛇身
    }

    // 绘制蛇头（黄色）
    coord.X = snake.x[0];  // 蛇头在最前面
    coord.Y = snake.y[0];
    SetConsoleCursorPosition(hConsole, coord);
    SetConsoleColor(14);  // 设置颜色为黄色
    printf("@");  // 绘制蛇头
    SetConsoleColor(15);  // 恢复默认颜色
}
void createMap() {
    int width = 50;  // 地图宽度
    int height = 20; // 地图高度

    // 打印顶部边界
    for (int i = 0; i < width; i++) {
        printf("#");
    }
    printf("\n");

    // 打印左右边界
    for (int i = 0; i < height - 2; i++) {
        printf("#");  // 左边界
        for (int j = 0; j < width - 2; j++) {
            printf(" "); // 空白区域
        }
        printf("#\n");  // 右边界
    }

    // 打印底部边界
    for (int i = 0; i < width; i++) {
        printf("#");
    }
    printf("\n");

    // 右侧区域绘制得分和提示
    COORD coord;
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    coord.X = width + 2; // 让提示在地图右侧
    coord.Y = 2;
    SetConsoleCursorPosition(hConsole, coord);
    printf("得分: 0");  // 初始得分

    coord.Y += 1;
    SetConsoleCursorPosition(hConsole, coord);
    printf("按 'W' 上, 'S' 下, 'A' 左, 'D' 右来控制蛇的移动");
}

// 显示分数和提示
void scoreandtips(int score) {
    COORD coord;
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    coord.X = 52;  // 右侧区域 X 坐标
    coord.Y = 2;
    SetConsoleCursorPosition(hConsole, coord);
    printf("得分: %d", score);  // 显示当前得分

    coord.Y += 1;
    SetConsoleCursorPosition(hConsole, coord);
    printf("按 'W' 上, 'S' 下, 'A' 左, 'D' 右来控制蛇的移动");
}

// 读取最高分
void File_out(int* highscore) {
    FILE *file = fopen("highscore.txt", "r");
    if (file == NULL) {
        *highscore = 0;  // 如果文件不存在，默认为0
    } else {
        fscanf(file, "%d", highscore);  // 读取分数
        fclose(file);
    }
}

// 初始化蛇
void initsnake() {
    int x = 24, y = 10;  // 修改为地图中间位置，避免靠近墙壁
    int snakeLength = 5;  // 初始蛇的长度
    snake.length = snakeLength;  // 初始化蛇的长度
    snake.dx = 1;  // 初始向右
    snake.dy = 0;  // 初始垂直方向

    // 初始化蛇身坐标
    for (int i = 0; i < snakeLength; i++) {
        snake.x[i] = x - i;  // 修改为递减 X 坐标，确保蛇头不与蛇身重合
        snake.y[i] = y;      // Y 坐标保持不变
    }
}

// 生成食物
void createfood() {
    if (foodX == -1 && foodY == -1) {  // 如果食物尚未生成
        srand(time(NULL));  // 初始化随机数种子
        foodX = rand() % 48 + 1;  // 在 1 到 48 之间生成随机数
        foodY = rand() % 18 + 1;  // 在 1 到 18 之间生成随机数
    }

    // 绘制食物（使用 '$' 表示食物）
    COORD coord = {foodX, foodY};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
    SetConsoleColor(12);  // 红色
    printf("$");
    SetConsoleColor(15);  // 恢复默认颜色
}

void clear_previous_snake_position() {
    COORD coord;
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

    // 清除蛇头和蛇身的旧位置
    for (int i = 0; i < snake.length; i++) {
        coord.X = snake.x[i];  // 获取蛇身的 X 坐标
        coord.Y = snake.y[i];  // 获取蛇身的 Y 坐标
        SetConsoleCursorPosition(hConsole, coord);
        printf(" ");  // 清除蛇身部分
    }
}

void game() {
    system("cls");
    hide_cursor();
    int score = 0;
    int highscore = load_highscore();

    File_out(&highscore);  // 获取历史最高分

    initsnake();  // 初始化蛇
    createMap();  // 创建地图
    createfood(); // 生成食物

    while (1) {
        flag : 
        handle_input();  // 处理输入
        clear_previous_snake_position();
        move_snake();    // 移动蛇

        if (check_wall_collision() || check_self_collision()) {
            gameover(score);
            system("cls");
            goto flag;
        }

        scoreandtips(score);  // 显示得分和提示

        // 检查是否吃到食物
        if (snake.x[0] == foodX && snake.y[0] == foodY) {
            score += score_per_food;  // 更新得分，依据加速或减速状态
            foodX = foodY = -1;  // 重新生成食物
            snake.length++;  // 增加蛇的长度
        }

        Sleep(sleeptime);  // 控制蛇的移动速度

        printsnake();   // 重新绘制蛇
        createfood();   // 重新绘制食物
    }
}

void gameover(int score) {
    int highscore = load_highscore();  // 获取最高分

    system("cls");
    if (score > highscore) {
        printf("创纪录啦！最高分被你刷新啦，真棒！！！\n");
        save_highscore(score);  // 保存新的最高分
    } else {
        printf("继续努力吧~你离最高分还差: %d\n", highscore - score);  // 显示距离最高分差多少
    }

    // 提示用户选择操作
    printf("\n1: 重玩\n2: 退出游戏\n请输入你的选择: ");
    int choice;
    while (1) {
        scanf("%d", &choice);
        if (choice == 1) {
            // 重玩
            game();  // 重新开始游戏
            return;  // 避免下面的代码执行
        } else if (choice == 2) {
            // 退出
            exit(0);  // 退出游戏
        } else {
            printf("输入错误，请重新选择: ");
        }
    }
}

void main_menu() {
    system("cls");
    SetConsoleColor(10);  // 绿色
    printf("\n\n");

    // 绘制美化后的蛇头和蛇身
    printf("                  @@@@@@@@\n");
    printf("                @@@@@@@@@@@@\n");
    printf("               @@@@@@@@@@@@@@@@\n");
    printf("              @@@@*@@@@@@@*@@@@\n");
    printf("             @@@@**@@@@@@**@@@@\n");
    printf("            @@@@****@@@@****@@@\n");
    printf("           @@@@@***@@@@***@@@@\n");
    printf("           @@@@***@@@@***@@@@\n");
    printf("           @@@@*@@@@@@@*@@@@\n");
    printf("            @@@@@@@@@@@@@@\n");
    printf("             @@@@@@@@@@@\n");
    printf("              @@@@@@@@\n");
    printf("              @@@@@@@\n");
    printf("              @@@@@@\n\n");
    printf("  _____                   _          _____                  _    ");
    printf(" / ____|                 | |        / ____|                | |   ");
    printf(" | |  __ _ __ ___  ___  __| |_   _  | (___  _ __   __ _  ___| | __");
    printf(" | | |_ | '__/ _ \\/ _ \\/ _` | | | |  \\___ \\| '_ \\ / _` |/ __| |/ /");
    printf(" | |__| | | |  __/  __/ (_| | |_| |  ____) | | | | (_| | (__|   <");
    printf("  \\_____|_|  \\___|\\___|\\__,_|\\__, | |_____/|_| |_|\\__,_|\\___|_|\\_\\");
    printf("                              __/ |                               ");
    printf("                             |___/                                ");
    
    SetConsoleColor(4);
    printf("        v0.1            --by B1ossoms_1010\n\n");

    // 恢复默认颜色
    SetConsoleColor(9);  // 白色
    printf("       欢迎来到贪吃蛇游戏！\n\n");
    printf("          1. 开始游戏\n\n");
    printf("          2. 游戏说明\n\n");
    printf("          3. 退出游戏\n\n"); 
    printf("      请输入你的选择: ");
    
    int choice;
    while (1) {
        scanf("%d", &choice);
        if (choice == 1) {
            game();  // 开始游戏
        } else if (choice == 2) {
            explation();  // 进入游戏说明界面
        } else if (choice == 3) {
            exit(0);  // 退出游戏
        } else {
            printf("输入错误，请重新选择: ");
        }
    }
}


int main() {

    main_menu();

    return 0;
}
